using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Perovich.GameObjects
{
    /// <summary>
    ///   Variant of the XNA GameComponent that doesn't reference the Game class
    /// </summary>
    /// <remarks>
    ///   <para>
    ///     This is a lightweight version of GameComponent that can be used without
    ///     requiring a Game class to be present. Useful to get all the advantages
    ///     of the XNA GameServices architecture even when you have initialized and
    ///     manage the graphics device yourself.
    ///   </para>
    ///   <para>
    ///     The name of this class is the same as 'GameComponent' minus the 'Game' part
    ///     as the Game reference is what this class removes from its namesake.
    ///   </para>
    /// </remarks>
    public abstract class Component : IGameComponent, IUpdateable
    {

        /// <summary>Triggered when the value of the <see cref="Component.Enabled"/> property is changed.</summary>
        public event EventHandler<EventArgs> EnabledChanged;

        /// <summary>Triggered when the value of the <see cref="Component.UpdateOrder"/> property is changed.</summary>
        public event EventHandler<EventArgs> UpdateOrderChanged;

        /// <summary>Initializes a new <see cref="Component"/>.</summary>
        /// <param name="parent">
        ///   <see cref="Perovich.GameObjects.Interfaces.ICanHoldComponents"/> instance that this <see cref="Component"/> will be constructed for.
        /// </param>
        protected Component(Interfaces.ICanSupportComponents parent)
        {
            if (parent == null)
                throw new ArgumentNullException("parent");
            
            this.services = parent.Services;
            this.enabled = true;
        }

        /// <summary>Gives the <see cref="Component"/> a chance to initialize itself</summary>
        public virtual void Initialize() {
            
        }

        /// <summary>Called when the <see cref="Component"/> needs to update its state.</summary>
        /// <param name="gameTime">Provides a snapshot of the Game's timing values</param>
        public virtual void Update(GameTime gameTime)
        {
        }

        /// <summary>
        ///   Indicates when the <see cref="Component"/> should be updated in relation to
        ///   other updateables. Has no effect by itself.
        /// </summary>
        public int UpdateOrder
        {
            get { return this.updateOrder; }
            set
            {
                if (value != this.updateOrder)
                {
                    this.updateOrder = value;
                    OnUpdateOrderChanged();
                }
            }
        }


        /// <summary>
        ///   True when the <see cref="Component"/> is enabled and should be udpated.
        /// </summary>
        public bool Enabled
        {
            get
            {
                return this.enabled;
            }
            set
            {
                if (value != this.enabled)
                {
                    this.enabled = value;
                    OnEnabledChanged();
                }
                
            }
        }

        /// <summary>Fires the UpdateOrderChanged event</summary>
        protected virtual void OnUpdateOrderChanged()
        {
            if (this.UpdateOrderChanged != null)
            {
                this.UpdateOrderChanged(this, EventArgs.Empty);
            }
        }

        /// <summary>Fires the EnabledChanged event</summary>
        protected virtual void OnEnabledChanged()
        {
            if (this.EnabledChanged != null)
            {
                this.EnabledChanged(this, EventArgs.Empty);
            }
        }

        /// <summary>Game service container the component was constructed for</summary>
        protected IServiceProvider GameServices
        {
            get { return this.services; }
        }

        private IServiceProvider services;
        private int updateOrder;
        private bool enabled;

    }
}
